use std::collections::HashMap;

struct Cache {
    storage: HashMap<String, String>,
    eviction_algo: Box<dyn EvictionAlgo>,
    capacity: usize,
    max_capacity: usize,
}

impl Cache {
    fn new(rec: Box<dyn EvictionAlgo>) -> Cache {
        return Cache {
            storage: Default::default(),
            eviction_algo: rec,
            capacity: 0,
            max_capacity: 2,
        };
    }
    fn eviction_algo(mut self, rec: Box<dyn EvictionAlgo>) {
        self.eviction_algo = rec
    }
    fn add(&mut self, key: String, value: String) {
        if self.capacity == self.max_capacity {
            self.evict();
        }
        self.storage.insert(key, value);
        self.capacity += 1;
    }
    fn evict(&mut self) {
        self.eviction_algo.evict(&mut self.storage);
        self.capacity -= 1;
    }
}

trait EvictionAlgo {
    fn evict(&self, c: &mut HashMap<String, String>);
}

struct Fifo {}

impl EvictionAlgo for Fifo {
    fn evict(&self, c: &mut HashMap<String, String>) {
        c.remove("aa");
        println!("Fifo remove");
    }
}

#[test]
fn main() {
    let fifo: Box<dyn EvictionAlgo> = Box::new(Fifo {});

    let cache = &mut Cache::new(fifo);
    // println!("storage:{:?}", cache.storage);
    println!("storage:{:?}", cache.storage);
    cache.add(String::from("aa"), String::from("aa"));
    cache.add(String::from("aa"), String::from("aa"));
    println!("storage:{:?}", cache.storage);
    cache.add(String::from("aa"), String::from("aa"));
    println!("storage:{:?}", cache.storage);
}